package com.example.bootdemo.controller;

import com.example.bootdemo.utils.R;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

import java.util.concurrent.CountDownLatch;
import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

@Slf4j
@RestController
@RequestMapping(value = "lock", produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
public class LockController {


    public static StringBuilder stringBuilder = new StringBuilder();

    public static AtomicInteger count = new AtomicInteger(0);

    public static int count1 = 0;

    private final static Lock lock = new ReentrantLock();

    private static final CyclicBarrier barrier = new CyclicBarrier(5);
    private static CyclicBarrier barrier1 = new CyclicBarrier(3, () -> {
        log.info("callback is running  3");
    });
    private static  CyclicBarrier cyclicBarrier = new CyclicBarrier(5,new Runnable() {
        @Override
        public void run() {
            System.out.println("5人已来,可以开席了");
        }
    });
    @RequestMapping(value = "info", method = RequestMethod.GET)
    public R info() {
        stringBuilder.append("1");
        log.info("size:{}", stringBuilder.length());
        return R.ok();

    }



    @RequestMapping(value = "atomicInteger", method = RequestMethod.GET)
    public R atomicInteger() {
        count.incrementAndGet();
        log.info("count:{}", count.get());
        return R.ok();

    }

    @RequestMapping(value = "atomicInteger1", method = RequestMethod.GET)
    public R atomicInteger1() {
        count.incrementAndGet();
        log.info("count:{}", count.get());
        return R.ok();

    }
    @RequestMapping(value = "reentrantLock", method = RequestMethod.GET)
    public R reentrantLock() {
        add();
        log.info("count:{}", count1);
        return R.ok();

    }
    private static void add() {
        lock.lock();
        try {
            count1++;
        } finally {
            lock.unlock();
        }
    }

    @RequestMapping(value = "barrier", method = RequestMethod.GET)
    public R barrier() throws Exception {
        final int threadNum = count1++;
        Thread.sleep(1000);
        race(threadNum);
        return R.ok();
    }
    @RequestMapping(value = "getNumberWaiting", method = RequestMethod.GET)
    public R getNumberWaiting() throws Exception {

        Thread.sleep(1000);
        int i=    barrier1.getNumberWaiting();
        return R.ok(String.valueOf(i));
    }



    @RequestMapping(value = "reset", method = RequestMethod.GET)
    public R reset() {

            barrier1.reset();
        return R.ok();
    }


    @RequestMapping(value = "parties", method = RequestMethod.GET)
    public R parties() {

        barrier1=new CyclicBarrier(2,()-> {
            log.info("callback is running  2");
        });

        log.info(" running  2");
        return R.ok();
    }

    @RequestMapping(value = "barrier1", method = RequestMethod.GET)
    public R barrier1() throws Exception {
        ExecutorService executor = Executors.newCachedThreadPool();

      //  for (int i = 0; i < 10; i++) { }
            final int threadNum = count1++;
            Thread.sleep(1000);
            executor.execute(() -> {
                try {
                    race(threadNum);
                } catch (Exception e) {
                    log.error("exception", e);
                }
            });

        executor.shutdown();
        return R.ok();

    }

   @RequestMapping(value = "barrier2", method = RequestMethod.GET)
    public R barrier2() throws Exception {
        ExecutorService executor = Executors.newCachedThreadPool();

        //  for (int i = 0; i < 10; i++) { }
        final int threadNum = count1++;
        Thread.sleep(1000);
        executor.execute(() -> {
            try {
                race2(threadNum);
            } catch (Exception e) {
                log.error("exception", e);
            }
        });

        executor.shutdown();
        return R.ok();

    }

    private  void race2(int threadNum) throws Exception {

        Thread.sleep(1000);
        log.info("{} is ready", threadNum);
        cyclicBarrier.await();
        log.info("{} continue", threadNum);
    }
    private static void race(int threadNum) throws Exception {
        Thread.sleep(1000);
        log.info("{} is ready", threadNum);
        barrier1.await();
        log.info("{} continue", threadNum);
    }
   @RequestMapping(value = "countDownLatch", method = RequestMethod.GET)
    public R countDownLatch() throws Exception {


        ExecutorService exec = Executors.newCachedThreadPool();

        final CountDownLatch countDownLatch = new CountDownLatch(200);


            final int threadNum =  count1++;
            exec.execute(() -> {
                try {
                    testcountDownLatch(threadNum);
                } catch (Exception e) {
                    log.error("exception", e);
                } finally {
                    countDownLatch.countDown();
                }
            });

        countDownLatch.await();
        log.info("finish");
        exec.shutdown();
        return R.ok();
    }
    private static void testcountDownLatch(int threadNum) throws Exception {
        Thread.sleep(100);
        log.info("{}", threadNum);
        Thread.sleep(100);
    }
}
